package server

import (
	"fmt"
	"github.com/emicklei/go-restful"
	"kubeInstall/conf"
	"kubeInstall/pkg/logger"
	"kubeInstall/server/routers"
	"kubeInstall/utils/request"
	"net/http"
	"time"
)

type ServerRunOptions struct {
	BindAddress string

	InsecurePort string

	// secure port number
	SecurePort int

	// tls cert file
	TlsCertFile string

	// tls private key file
	TlsPrivateKey string
	ReadTimeout   time.Duration
	WriteTimeout  time.Duration

	RunMode string
}

func NewServerRunOptions() *ServerRunOptions {
	s := ServerRunOptions{
		BindAddress:   "0.0.0.0",
		InsecurePort:  conf.ServerSetting.HttpPort,
		SecurePort:    0,
		TlsCertFile:   "",
		TlsPrivateKey: "",
		RunMode:       conf.ServerSetting.RunMode,
		ReadTimeout:   conf.ServerSetting.ReadTimeout,
		WriteTimeout:  conf.ServerSetting.WriteTimeout,
	}

	return &s
}

type APIServer struct {
	Server *http.Server

	container *restful.Container
}

func NewAPIServer(options *ServerRunOptions) *APIServer {
	s := new(APIServer)
	logger.SetLoggerInit()

	s.container = restful.NewContainer()
	s.container.EnableContentEncoding(true)
	s.container.Filter(logRequestAndResponse)
	s.container.Router(restful.CurlyRouter{})

	r := routers.InitRouter()
	for _, ws := range r.Ws {
		s.container.Add(ws)
		for _, r := range ws.Routes() {
			logger.Debug("%s %s", r.Method, r.Path)
		}
	}

	maxHeaderBytes := 1 << 20

	endPoint := fmt.Sprintf(":%s", options.InsecurePort)
	s.Server = &http.Server{
		Addr:           endPoint,
		ReadTimeout:    options.ReadTimeout,
		WriteTimeout:   options.WriteTimeout,
		MaxHeaderBytes: maxHeaderBytes,
		Handler:        s.container,
	}

	logger.Info("start http server listening %s", endPoint)
	return s
}

func (s *APIServer) Run() {

	if s.Server.TLSConfig != nil {
		logger.Fatal(s.Server.ListenAndServeTLS("", ""))
	} else {
		logger.Fatal(s.Server.ListenAndServe())
	}

}

func logRequestAndResponse(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	start := time.Now()
	chain.ProcessFilter(req, resp)
	msg := "success"

	if resp.StatusCode() >= 400 {
		msg = "failed"
	}
	logger.Debug("[Request] [%s] %s - \"%s %s\" %d %d %dms",
		msg,
		request.GetRequestIP(req),
		req.Request.Method,
		req.Request.RequestURI,
		resp.StatusCode(),
		resp.ContentLength(),
		time.Since(start)/time.Millisecond)
}
